package com.ljy.my_study.leetcode.滑动谜题;

import java.util.*;

public class TestMain {

//    在一个 2 x 3 的板上（board）有 5 块砖瓦，用数字 1~5 来表示, 以及一块空缺用 0 来表示.
//
//            一次移动定义为选择 0 与一个相邻的数字（上下左右）进行交换.
//
//            最终当板 board 的结果是 [[1,2,3],[4,5,0]] 谜板被解开。
//
//    给出一个谜板的初始状态，返回最少可以通过多少次移动解开谜板，如果不能解开谜板，则返回 -1 。
//
//    示例：
//
//    输入：board = [[1,2,3],[4,0,5]]
//    输出：1
//    解释：交换 0 和 5 ，1 步完成
//    输入：board = [[1,2,3],[5,4,0]]
//    输出：-1
//    解释：没有办法完成谜板
//    输入：board = [[4,1,2],[5,0,3]]
//    输出：5
//    解释：
//    最少完成谜板的最少移动次数是 5 ，
//    一种移动路径:
//    尚未移动: [[4,1,2],[5,0,3]]
//    移动 1 次: [[4,1,2],[0,5,3]]
//    移动 2 次: [[0,1,2],[4,5,3]]
//    移动 3 次: [[1,0,2],[4,5,3]]
//    移动 4 次: [[1,2,0],[4,5,3]]
//    移动 5 次: [[1,2,3],[4,5,0]]
//    输入：board = [[3,2,4],[1,5,0]]
//    输出：14
//    提示：
//
//    board 是一个如上所述的 2 x 3 的数组.
//            board[i][j] 是一个 [0, 1, 2, 3, 4, 5] 的排列.
//
//            来源：力扣（LeetCode）
//    链接：https://leetcode-cn.com/problems/sliding-puzzle
//    著作权归领扣网络所有。商业转载请联系官方授权，非商业转载请注明出处。

    public static void main(String[] args) {
        int[][] board=new int[][]{{4,1,2},{5,0,3}};
        System.out.println(new TestMain().slidingPuzzle(board));
    }

    public int slidingPuzzle(int[][] board) {
        String start=transfer(board);
        String end="123450";
        if(start.equals(end)){
            return 0;
        }
        Set<String> set=new HashSet<>();
        Queue<String> queue=new LinkedList<>();
        queue.offer(start);
        set.add(start);
        int step=0;
        while(!queue.isEmpty()){
            step++;
            int size=queue.size();
            for(int i=0;i<size;i++){
                String b=queue.poll();
                for(String next:getNext(b)){
                    if(next.equals(end)){
                        return step;
                    }
                    if(!set.contains(next)){
                        queue.offer(next);
                        set.add(next);
                    }
                }
            }
        }
        return -1;
    }

    private String transfer(int[][] board){
        StringBuilder sb=new StringBuilder();
        for(int i=0;i<board.length;i++){
            for(int j=0;j<board[0].length;j++){
                sb.append(board[i][j]);
            }
        }
        return sb.toString();
    }

    private List<String> getNext(String board){
        char[] chars=board.toCharArray();
        int i=0;
        for(;i<chars.length;i++){
            if(chars[i]=='0'){
                break;
            }
        }
        List<String> list=new ArrayList<>();
        if(i-1>=0&&i-1!=2){
            list.add(getStr(chars,i-1,i));
        }
        if(i+1<=5&&i+1!=3){
            list.add(getStr(chars,i,i+1));
        }
        list.add(getStr(chars,i%3,i%3+3));
        return list;
    }

    private String getStr(char[] chars,int oneIndex,int twoIndex){
        char[] newChars=chars.clone();
        char flag=newChars[oneIndex];
        newChars[oneIndex]=newChars[twoIndex];
        newChars[twoIndex]=flag;
        return String.valueOf(newChars);
    }
}
